<?php
/**
 * Description:  Handle creating and sending emails
 * Applications utilizing this file: Vanilla;
 *
 * Copyright 2003 Mark O'Sullivan
 * This file is part of Lussumo's Software Library.
 * Lussumo's Software Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 * Lussumo's Software Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with Vanilla; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * The latest source code is available at www.lussumo.com
 * Contact Mark O'Sullivan at mark [at] lussumo [dot] com
 *
 * @author Mark O'Sullivan
 * @copyright 2003 Mark O'Sullivan
 * @license http://lussumo.com/community/gpl.txt GPL 2
 * @package Framework
 * @version 1.1.2
 */

/**
 * Handle creating and sending emails
 * @package Framework
 */
class Email
{
    private $Recipients;    // Array of recipients
    private $CCRecipients;  // Array of cc'd recipients
    private $BCCRecipients; // Array of bcc'd recipients
    private $FromName;      // String
    private $FromEmail;     // String
    private $Subject;       // Subject line of the email
    private $Body;
    private $FatalError;    // Throw a fatal error if the mail fails to send? (default true)

    // Standard properties
    private $Name;          // The name of this class
    private $Context;

    /**
     * __construct
     *
     * @access public
     */
    public function __construct()
    {
        $this->Clear();
        $this->Context = Context::getInstance();
    }

    /**
     * AddBCCRecipient
     *
     * @access public
     * @param  string $Email
     * @param  string $Name
     * @uses   self::addTo()
     * @return void
     */
    public function AddBCCRecipient($Email, $Name = '')
    {
        $this->AddTo('BCCRecipients', $Email, $Name);
    }

    /**
     * AddCCRecipient
     *
     * @access public
     * @param  string $Email
     * @param  string $Name
     * @uses   self::addTo()
     * @return void
     */
    public function AddCCRecipient($Email, $Name = '')
    {
        $this->AddTo('CCRecipients', $Email, $Name);
    }

    /**
     * AddFrom
     *
     * @access public
     * @param  string $Email
     * @param  string $Name
     * @uses   self::$FromEmail
     * @uses   self::$FromName
     * @return void
     */	
    public function AddFrom($Email, $Name = '')
    {
        $this->FromEmail = $Email;
        $this->FromName  = $Name;
    }

    /**
     * AddRecipient
     *
     * @access public
     * @param  string $Email
     * @param  string $Name
     * @uses   self::addTo()
     * @return void
     */
    public function AddRecipient($Email, $Name = '')
    {
        $this->AddTo('Recipients', $Email, $Name);
    }

    /**
     * AddTo
     *
     * @access private
     * @param  string $ToType
     * @param  string $Email
     * @param  string $Name
     * @return void
     */
    private function AddTo($ToType, $Email, $Name = '')
    {
        $Found = false;
        if ($this->$ToType) {
            foreach ($this->$ToType as $key => $value) {
                if ($value['Email'] == $Email) {
                    $Found = true;
                }
            }
        }

        if ($Found === false) {
            if ($ToType == 'Recipients') {
                if (count($this->Recipients) >= 1) {
                    $this->CCRecipients[] = array('Email' => $Email, 'Name' => $Name);
                } else {
                    $this->Recipients[] = array('Email' => $Email, 'Name' => $Name);
                }
            } elseif ($ToType == 'CCRecipients') {
                $this->CCRecipients[] = array('Email' => $Email, 'Name' => $Name);
            } elseif ($ToType == 'BCCRecipients') {
                $this->BCCRecipients[] = array('Email' => $Email, 'Name' => $Name);
            }
        }
    }

    /**
     * AddToHeader
     *
     * @access private
     * @param  string $ToType
     * @param  ezcMail $mail
     * @todo   Rename this function, it's more a GET than a SET (~= AddTo...)
     * @return ezcMail
     */
    private function AddToHeader($ToType, ezcMail $mail)
    {
        $ToTypeCount = count($this->$ToType);
        for ($i = 0; $i < $ToTypeCount; $i++) {
            if ($ToType == 'CCRecipients') {
                $mail->addCc(new ezcMailAddress($this->CCRecipients[$i]['Email'], $this->CCRecipients[$i]['Name']));
            } elseif ($ToType == 'BCCRecipients') {
                $mail->addBcc(new ezcMailAddress($this->BCCRecipients[$i]['Email'], $this->BCCRecipients[$i]['Name']));
            }
        }

        return $mail;
    }

    /**
     * Clear
     *
     * @access private
     * @return void
     * @see    self::__construct()
     */
    private function Clear()
    {
        $this->Name       = 'Email';
        $this->FromName   = '';
        $this->FromEmail  = '';
        $this->Subject    = '';
        $this->Body       = '';
        $this->FatalError = 1;

        $this->ClearRecipients();
    }

    /**
     * ClearRecipients
     *
     * @access public
     * @return void
     */
    public function ClearRecipients()
    {
        $this->Recipients    = array();
        $this->CCRecipients  = array();
        $this->BCCRecipients = array();
    }

    /**
     * Send
     *
     * Attemps to send an email. Will return true in case everything went well
     * and false otherwise. According to general Vanilla behaviour, code might
     * also die in the middle of execution when a "fatal" error occurs.
     *
     * @access public
     * @param  int $FatalError
     * @return boolean
     * @uses   ezcMailComposer
     * @uses   self::$FatalError
     * @uses   self::ValideEmail()
     * @uses   self::$Recipients
     * @uses   self::$CCRecipients
     * @uses   self::$BCCRecipients
     * @uses   self::$Subject
     * @uses   self::$Body
     * @uses   self::SMTPSend()
     */
    public function Send($FatalError = 1)
    {
        $this->FatalError = $FatalError;

        // Check that required properties are supplied
        if ($this->ValidateEmail() !== true) {
            return false;
        }
        $To = $this->Recipients[0]['Email'];

        $mail = new ezcMailComposer();

        $mail->addTo(new ezcMailAddress($to));
        $mail->from = new ezcMailAddress($this->FromEmail, $this->FromName);

        if (count($this->CCRecipients) > 0) {
            $mail = $this->AddToHeader('CCRecipients', $mail);
        }
        if (count($this->BCCRecipients) > 0) {
            $mail = $this->AddToHeader('BCCRecipients', $mail);
        }

        $mail->subject   = $this->Subject;
        $mail->plainText = $this->Body;

        $mail->__set('charset', $this->Context->Configuration['CHARSET']);
        $mail->setHeader('X-Mailer', 'Vanillin Mailer');
        $mail->setHeader('Reply-To', $this->FromEmail);
        $mail->setHeader('Errors-To', $this->FromEmail);

        $mail->build();

        if (!empty($this->Context->Configuration['SMTP_HOST'])) {
            $status = $this->SMTPSend($To, $this->Subject, $Message, $Header);
            return $status;
        }

        try {
            $transport = new ezcMailMtaTransport();
            $transport->send($mail);
        } catch (ezcMailTransportException $e) {
            $this->Context->ErrorManager->AddError(
                        $this->Context,
                        $this->Name,
                        'Send',
                        'An error occurred while sending the email.',
                        $e->getMessage()
            );
        }

        return true;
    }

    /**
     * SMTPSend
     *
     * @access private
     * @param  ezcMailComposer $mail
     * @return bool
     */
    private function SMTPSend(ezcMail $mail)
    {
        // Are we using port 25 or a custom port?
        if (strpos($this->Context->Configuration['SMTP_HOST'], ':') !== false) {
            list($SMTPHost, $SMTPPort) = explode(':', $this->Context->Configuration['SMTP_HOST']);
        } else {
            $SMTPHost = $this->Context->Configuration['SMTP_HOST'];
            $SMTPPort = 25;
        }
        $SMTPUser = '';
        $SMTPPass = '';
        if (!empty($this->Context->Configuration['SMTP_USER'])) {
            $SMTPUser.= $this->Context->Configuration['SMTP_USER'];
        }
        if (!empty($this->Context->Configuration['SMTP_PASSWORD'])) {
            $SMTPPass.= $this->Context->Configuration['SMTP_PASSWORD'];
        }

        try {
            $transport = new ezcMailSmtpTransport(
                                $SMTPHost,
                                $SMTPUser,
                                $SMTPPass,
                                $SMTPPort
            );
            $transport->send($mail);
        } catch (ezcMailTransportException $e) {
            $ErrorString = $e->getMessage();
            $ErrorNumber = $e->getCode();
            if (!$this->FatalError) {
                return false;
            }

            $this->Context->ErrorManager->AddError(
                            $this->Context,
                            $this->Name,
                            'SMTPSend',
                            $ErrorNumber.': '.$ErrorString
            );
        }


        return true;
    }

    /**
     * ServerParse
     *
     * @access private
     * @return void
     * @deprecated
     */
    private function ServerParse()
    {}

    /**
     * ValidateEmail
     *
     * Checks if subject, from and recipients are set.
     *
     * @access private
     * @return
     */
    private function ValidateEmail()
    {
        $this->Subject = str_replace(array("\r","\n"),"",$this->Subject);

        if (empty($this->Subject)) {
            $this->Context->WarningCollector->Add($this->Context->GetDefinition('ErrEmailSubject'));
        }
        if (empty($this->Recipients)) {
            $this->Context->WarningCollector->Add($this->Context->GetDefinition('ErrEmailRecipient'));
        }
        if (empty($this->FromEmail)) {
            $this->Context->WarningCollector->Add($this->Context->GetDefinition('ErrEmailFrom'));
        }
        if (empty($this->Body)) {
            $this->Context->WarningCollector->Add($this->Context->GetDefinition('ErrEmailBody'));
        }
        return $this->Context->WarningCollector->Iif();
    }
}
